
package com.fluidops.datacatalog.reltables.util.stemmer;
import java.lang.reflect.InvocationTargetException;

public class SnowballProgram {
	protected SnowballProgram()
	{
		current = new StringBuffer();
		setCurrent("");
	}

	/**
	 * Set the current string.
	 */
	public void setCurrent(String value)
	{
		current.replace(0, current.length(), value);
		cursor = 0;
		limit = current.length();
		limit_backward = 0;
		bra = cursor;
		ket = limit;
	}

	/**
	 * Get the current string.
	 */
	public String getCurrent()
	{
		String result = current.toString();
		// Make a new StringBuffer.  If we reuse the old one, and a user of
		// the library keeps a reference to the buffer returned (for example,
		// by converting it to a String in a way which doesn't force a copy),
		// the buffer size will not decrease, and we will risk wasting a large
		// amount of memory.
		// Thanks to Wolfram Esser for spotting this problem.
		current = new StringBuffer();
		return result;
	}

	// current string
	protected StringBuffer current;

	protected int cursor;
	protected int limit;
	protected int limit_backward;
	protected int bra;
	protected int ket;

	protected void copy_from(SnowballProgram other)
	{
		current          = other.current;
		cursor           = other.cursor;
		limit            = other.limit;
		limit_backward   = other.limit_backward;
		bra              = other.bra;
		ket              = other.ket;
	}

	protected boolean in_grouping(char [] s, int min, int max)
	{
		if (cursor >= limit) return false;
		char ch = current.charAt(cursor);
		if (ch > max || ch < min) return false;
		ch -= min;
		if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return false;
		cursor++;
		return true;
	}

	protected boolean in_grouping_b(char [] s, int min, int max)
	{
		if (cursor <= limit_backward) return false;
		char ch = current.charAt(cursor - 1);
		if (ch > max || ch < min) return false;
		ch -= min;
		if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return false;
		cursor--;
		return true;
	}

	protected boolean out_grouping(char [] s, int min, int max)
	{
		if (cursor >= limit) return false;
		char ch = current.charAt(cursor);
		if (ch > max || ch < min) {
			cursor++;
			return true;
		}
		ch -= min;
		if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) {
			cursor ++;
			return true;
		}
		return false;
	}

	protected boolean out_grouping_b(char [] s, int min, int max)
	{
		if (cursor <= limit_backward) return false;
		char ch = current.charAt(cursor - 1);
		if (ch > max || ch < min) {
			cursor--;
			return true;
		}
		ch -= min;
		if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) {
			cursor--;
			return true;
		}
		return false;
	}

	protected boolean in_range(int min, int max)
	{
		if (cursor >= limit) return false;
		char ch = current.charAt(cursor);
		if (ch > max || ch < min) return false;
		cursor++;
		return true;
	}

	protected boolean in_range_b(int min, int max)
	{
		if (cursor <= limit_backward) return false;
		char ch = current.charAt(cursor - 1);
		if (ch > max || ch < min) return false;
		cursor--;
		return true;
	}

	protected boolean out_range(int min, int max)
	{
		if (cursor >= limit) return false;
		char ch = current.charAt(cursor);
		if (!(ch > max || ch < min)) return false;
		cursor++;
		return true;
	}

	protected boolean out_range_b(int min, int max)
	{
		if (cursor <= limit_backward) return false;
		char ch = current.charAt(cursor - 1);
		if(!(ch > max || ch < min)) return false;
		cursor--;
		return true;
	}

	protected boolean eq_s(int s_size, String s)
	{
		if (limit - cursor < s_size) return false;
		int i;
		for (i = 0; i != s_size; i++) {
			if (current.charAt(cursor + i) != s.charAt(i)) return false;
		}
		cursor += s_size;
		return true;
	}

	protected boolean eq_s_b(int s_size, String s)
	{
		if (cursor - limit_backward < s_size) return false;
		int i;
		for (i = 0; i != s_size; i++) {
			if (current.charAt(cursor - s_size + i) != s.charAt(i)) return false;
		}
		cursor -= s_size;
		return true;
	}

	protected boolean eq_v(CharSequence s)
	{
		return eq_s(s.length(), s.toString());
	}

	protected boolean eq_v_b(CharSequence s)
	{   return eq_s_b(s.length(), s.toString());
	}

	protected int find_among(Among v[], int v_size)
	{
		int i = 0;
		int j = v_size;

		int c = cursor;
		int l = limit;

		int common_i = 0;
		int common_j = 0;

		boolean first_key_inspected = false;

		while(true) {
			int k = i + ((j - i) >> 1);
			int diff = 0;
			int common = common_i < common_j ? common_i : common_j; // smaller
			Among w = v[k];
			int i2;
			for (i2 = common; i2 < w.s_size; i2++) {
				if (c + common == l) {
					diff = -1;
					break;
				}
				diff = current.charAt(c + common) - w.s[i2];
				if (diff != 0) break;
				common++;
			}
			if (diff < 0) {
				j = k;
				common_j = common;
			} else {
				i = k;
				common_i = common;
			}
			if (j - i <= 1) {
				if (i > 0) break; // v->s has been inspected
				if (j == i) break; // only one item in v

				// - but now we need to go round once more to get
				// v->s inspected. This looks messy, but is actually
				// the optimal approach.

				if (first_key_inspected) break;
				first_key_inspected = true;
			}
		}
		while(true) {
			Among w = v[i];
			if (common_i >= w.s_size) {
				cursor = c + w.s_size;
				if (w.method == null) return w.result;
				boolean res;
				try {
					Object resobj = w.method.invoke(w.methodobject,
							new Object[0]);
					res = resobj.toString().equals("true");
				} catch (InvocationTargetException e) {
					res = false;
					// FIXME - debug message
				} catch (IllegalAccessException e) {
					res = false;
					// FIXME - debug message
				}
				cursor = c + w.s_size;
				if (res) return w.result;
			}
			i = w.substring_i;
			if (i < 0) return 0;
		}
	}

	// find_among_b is for backwards processing. Same comments apply
	protected int find_among_b(Among v[], int v_size)
	{
		int i = 0;
		int j = v_size;

		int c = cursor;
		int lb = limit_backward;

		int common_i = 0;
		int common_j = 0;

		boolean first_key_inspected = false;

		while(true) {
			int k = i + ((j - i) >> 1);
			int diff = 0;
			int common = common_i < common_j ? common_i : common_j;
			Among w = v[k];
			int i2;
			for (i2 = w.s_size - 1 - common; i2 >= 0; i2--) {
				if (c - common == lb) {
					diff = -1;
					break;
				}
				diff = current.charAt(c - 1 - common) - w.s[i2];
				if (diff != 0) break;
				common++;
			}
			if (diff < 0) {
				j = k;
				common_j = common;
			} else {
				i = k;
				common_i = common;
			}
			if (j - i <= 1) {
				if (i > 0) break;
				if (j == i) break;
				if (first_key_inspected) break;
				first_key_inspected = true;
			}
		}
		while(true) {
			Among w = v[i];
			if (common_i >= w.s_size) {
				cursor = c - w.s_size;
				if (w.method == null) return w.result;

				boolean res;
				try {
					Object resobj = w.method.invoke(w.methodobject,
							new Object[0]);
					res = resobj.toString().equals("true");
				} catch (InvocationTargetException e) {
					res = false;
					// FIXME - debug message
				} catch (IllegalAccessException e) {
					res = false;
					// FIXME - debug message
				}
				cursor = c - w.s_size;
				if (res) return w.result;
			}
			i = w.substring_i;
			if (i < 0) return 0;
		}
	}

	/* to replace chars between c_bra and c_ket in current by the
	 * chars in s.
	 */
	protected int replace_s(int c_bra, int c_ket, String s)
	{
		int adjustment = s.length() - (c_ket - c_bra);
		current.replace(c_bra, c_ket, s);
		limit += adjustment;
		if (cursor >= c_ket) cursor += adjustment;
		else if (cursor > c_bra) cursor = c_bra;
		return adjustment;
	}

	protected void slice_check()
	{
		if (bra < 0 ||
				bra > ket ||
				ket > limit ||
				limit > current.length())   // this line could be removed
		{
			System.err.println("faulty slice operation");
			// FIXME: report error somehow.
			/*
	    fprintf(stderr, "faulty slice operation:\n");
	    debug(z, -1, 0);
	    exit(1);
			 */
		}
	}

	protected void slice_from(String s)
	{
		slice_check();
		replace_s(bra, ket, s);
	}

	protected void slice_from(CharSequence s)
	{
		slice_from(s.toString());
	}

	protected void slice_del()
	{
		slice_from("");
	}

	protected void insert(int c_bra, int c_ket, String s)
	{
		int adjustment = replace_s(c_bra, c_ket, s);
		if (c_bra <= bra) bra += adjustment;
		if (c_bra <= ket) ket += adjustment;
	}

	protected void insert(int c_bra, int c_ket, CharSequence s)
	{
		insert(c_bra, c_ket, s.toString());
	}

	/* Copy the slice into the supplied StringBuffer */
	@SuppressWarnings("unused")
	protected StringBuffer slice_to(StringBuffer s)
	{
		slice_check();
		int len = ket - bra;
		s.replace(0, s.length(), current.substring(bra, ket));
		return s;
	}

	/* Copy the slice into the supplied StringBuilder */
	@SuppressWarnings("unused")
	protected StringBuilder slice_to(StringBuilder s)
	{
		slice_check();
		int len = ket - bra;
		s.replace(0, s.length(), current.substring(bra, ket));
		return s;
	}

	protected StringBuffer assign_to(StringBuffer s)
	{
		s.replace(0, s.length(), current.substring(0, limit));
		return s;
	}

	protected StringBuilder assign_to(StringBuilder s)
	{
		s.replace(0, s.length(), current.substring(0, limit));
		return s;
	}

	/*
extern void debug(struct SN_env * z, int number, int line_count)
{   int i;
    int limit = SIZE(z->p);
    //if (number >= 0) printf("%3d (line %4d): '", number, line_count);
    if (number >= 0) printf("%3d (line %4d): [%d]'", number, line_count,limit);
    for (i = 0; i <= limit; i++)
    {   if (z->lb == i) printf("{");
        if (z->bra == i) printf("[");
        if (z->c == i) printf("|");
        if (z->ket == i) printf("]");
        if (z->l == i) printf("}");
        if (i < limit)
        {   int ch = z->p[i];
            if (ch == 0) ch = '#';
            printf("%c", ch);
        }
    }
    printf("'\n");
}
	 */

};
